{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# bqplot: complex interactive visualizations\n",
    "\n",
    "## https://github.com/bloomberg/bqplot\n",
    "\n",
    "## A Jupyter - d3.js bridge\n",
    "\n",
    "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n",
    "\n",
    "- Apache Licensed\n",
    "\n",
    "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n",
    "\n",
    "bqplot provides both\n",
    "-\thigh-level plotting procedures with relevant defaults for common chart types,\n",
    "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge bqplot\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "from IPython.display import display\n",
    "from ipywidgets import *\n",
    "from traitlets import *\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import bqplot as bq\n",
    "import datetime as dt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(0)\n",
    "size = 100\n",
    "y_data = np.cumsum(np.random.randn(size) * 100.0)\n",
    "y_data_2 = np.cumsum(np.random.randn(size))\n",
    "y_data_3 = np.cumsum(np.random.randn(size) * 100.)\n",
    "\n",
    "x = np.linspace(0.0, 10.0, size)\n",
    "\n",
    "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.8], [0.8, 1.0]]), axis=0) + 100,\n",
    "                          columns=['Security 1', 'Security 2'],\n",
    "                          index=pd.date_range(start='01-01-2007', periods=150))\n",
    "\n",
    "symbol = 'Security 1'\n",
    "dates_all = price_data.index.values\n",
    "final_prices = price_data[symbol].values.flatten()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A simple plot with the pyplot API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from bqplot import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ce93314362854c96901f3f0144bc57a3",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(1)\n",
    "n = 100\n",
    "plt.plot(np.linspace(0.0, 10.0, n), np.cumsum(np.random.randn(n)), \n",
    "         axes_options={'y': {'grid_lines': 'dashed'}})\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Scatter Plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9475b0c975424d7b854c6ffdb02b5646",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(title='Scatter Plot with colors')\n",
    "plt.scatter(y_data_2, y_data_3, color=y_data)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Histogram"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e46996f4fdcb428e8949213c4d550491",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure()\n",
    "plt.hist(y_data, colors=['OrangeRed'])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Every component of the figure is an independent widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0cdfaeb7eb3a436a9a54d0c3c9334e51",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x = np.arange(100)\n",
    "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n",
    "\n",
    "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n",
    "\n",
    "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# update data of the line mark\n",
    "line.y = np.cumsum(np.random.randn(2, 100), axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "08906a17e54945cca701750e553e0bd2",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x, y = np.random.rand(2, 20)\n",
    "scatt = bq.Scatter(x=x, y=y, scales={'x': xs, 'y': ys}, default_colors=['blue'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n",
    "\n",
    "fig = bq.Figure(marks=[scatt], axes=[xax, yax], animation_duration=1000)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#data updates\n",
    "scatt.x = np.random.rand(20) * 10\n",
    "scatt.y = np.random.rand(20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The same holds for the attributes of scales, axes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xs.min = 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xs.min = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xax.label = 'Some label for the x axis'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Use bqplot figures as input widgets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x = np.arange(100)\n",
    "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n",
    "\n",
    "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Selections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "fc18c480beaa4abfa8642e8636ff0b08",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def interval_change_callback(change):\n",
    "    db.value = str(change['new'])\n",
    "\n",
    "intsel = bq.interacts.FastIntervalSelector(scale=xs, marks=[line])\n",
    "intsel.observe(interval_change_callback, names=['selected'] )\n",
    "\n",
    "db = widgets.Label()\n",
    "db.value = str(intsel.selected)\n",
    "display(db)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7c5241acd5b244aabdc12964899dd480",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000, interaction=intsel)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "line.selected"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Handdraw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "handdraw = bq.interacts.HandDraw(lines=line)\n",
    "fig.interaction = handdraw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.72310049,  0.74771262,  1.46769635,  0.36479014,  0.26309286,\n",
       "        0.28237225,  2.13196349,  1.91779684,  1.4187802 ,  1.44013142,\n",
       "        0.52101798,  0.71377183,  0.34871661, -1.44261094, -1.50119749,\n",
       "       -1.81874058, -3.45116389, -3.51829804, -2.02894208, -1.50763833,\n",
       "       -0.89571114, -2.23720786, -1.76030949, -1.61185991, -1.08281467,\n",
       "       -0.66018605, -2.01996678, -2.06136759, -2.81923845, -2.86932254,\n",
       "       -3.76672347, -2.4542531 , -3.31322549, -4.21216765, -4.13758124,\n",
       "       -5.21468031, -5.63934361, -6.46930821, -5.05813615, -4.27233232,\n",
       "       -4.32980184, -4.72101889, -3.78010128, -3.3748972 , -2.87684479,\n",
       "       -2.90303703, -4.59126706, -4.70373304, -5.23622296, -4.59116768,\n",
       "       -3.57932525, -4.2372763 , -3.76889106, -2.03301206, -2.70072479,\n",
       "       -1.01880305, -1.87138889, -1.84842914, -1.85957475, -1.84807585,\n",
       "       -2.68575389, -3.27693699, -3.94465728, -3.61769469, -3.28765957,\n",
       "       -1.06171524,  0.30927377, -0.20056947,  0.12430014,  1.12141812,\n",
       "        1.15201995,  1.08237837,  1.13395331,  2.00122994,  1.15290942,\n",
       "        0.82723995,  1.29767309,  1.60912016,  1.84870292,  1.47890176,\n",
       "        2.45143755,  4.58530579,  4.99172129,  4.79854459,  5.55428487,\n",
       "        5.01515224,  4.26546189,  4.29827064,  1.71547401,  0.56152364,\n",
       "        0.21356179, -1.13982707, -2.17247017, -2.60921851, -4.2521838 ,\n",
       "       -4.6582556 , -5.19352576, -5.16812055, -4.01393652, -3.84143211])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "line.y[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Moving points around"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<bqplot.marks.Label at 0x11a0dcb70>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2b442a6ed38443979345d6fe01eda274",
       "version_major": "2",
       "version_minor": "0"
      },
      "text/plain": [
       "A Jupyter Widget"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from bqplot import *\n",
    "\n",
    "size = 100\n",
    "np.random.seed(0)\n",
    "x_data = range(size)\n",
    "y_data = np.cumsum(np.random.randn(size) * 100.0)\n",
    "\n",
    "## Enabling moving of points in scatter. Try to click and drag any of the points in the scatter and \n",
    "## notice the line representing the mean of the data update\n",
    "\n",
    "sc_x = LinearScale()\n",
    "sc_y = LinearScale()\n",
    "\n",
    "scat = Scatter(x=x_data[:10], y=y_data[:10], scales={'x': sc_x, 'y': sc_y}, default_colors=['blue'],\n",
    "               enable_move=True)\n",
    "lin = Lines(scales={'x': sc_x, 'y': sc_y}, stroke_width=4, line_style='dashed', colors=['orange'])\n",
    "m = Label(value='Mean is %s'%np.mean(scat.y))\n",
    "\n",
    "def update_line(change):\n",
    "    with lin.hold_sync():\n",
    "        lin.x = [np.min(scat.x), np.max(scat.x)]\n",
    "        lin.y = [np.mean(scat.y), np.mean(scat.y)]\n",
    "        m.value='Mean is %s'%np.mean(scat.y)\n",
    "        \n",
    "\n",
    "update_line(None)\n",
    "\n",
    "# update line on change of x or y of scatter\n",
    "scat.observe(update_line, names='x')\n",
    "scat.observe(update_line, names='y')\n",
    "\n",
    "ax_x = Axis(scale=sc_x)\n",
    "ax_y = Axis(scale=sc_y, tick_format='0.2f', orientation='vertical')\n",
    "\n",
    "fig = Figure(marks=[scat, lin], axes=[ax_x, ax_y])\n",
    "\n",
    "## In this case on drag, the line updates as you move the points.\n",
    "with scat.hold_sync():\n",
    "    scat.enable_move = True\n",
    "    scat.update_on_move = True\n",
    "    scat.enable_add = False\n",
    "\n",
    "display(m, fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "widgets-tutorial",
   "language": "python",
   "name": "widgets-tutorial"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "widgets": {
   "state": {
    "0ba98b0561564e5987dba19d1b574c04": {
     "views": [
      {
       "cell_index": 29
      }
     ]
    },
    "1ffa1ac6658e4eef89e45cf62daae339": {
     "views": [
      {
       "cell_index": 30
      }
     ]
    },
    "42735872becb4c43b817ccff90973d63": {
     "views": [
      {
       "cell_index": 15
      }
     ]
    },
    "4b9a5b18593545faba761a719b2e6039": {
     "views": [
      {
       "cell_index": 17
      }
     ]
    },
    "7fb14b25d15240ec820c565619fe4f11": {
     "views": [
      {
       "cell_index": 7
      }
     ]
    },
    "99604f1b70c54e19a508c95d705ce488": {
     "views": [
      {
       "cell_index": 9
      }
     ]
    },
    "bf805af773d94496888afbe9e2bd3d37": {
     "views": [
      {
       "cell_index": 13
      }
     ]
    },
    "dc1b84a0e5fa4ed5a42454cfc52c44f5": {
     "views": [
      {
       "cell_index": 25
      }
     ]
    },
    "f30275bcf69e426c9d45a525833198d0": {
     "views": [
      {
       "cell_index": 5
      }
     ]
    }
   },
   "version": "2.0.0-dev"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
